/*
 * Copyright (c) 2018 Kryptos Logic
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *   3. Neither the name of the copyright holder nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "name.h"

#include "vmx.h"

const char *name_vmcs_component(int value)
{
    // The following macro compactifies the VMCS component encoding to 9 bits,
    // thus all major compilers will optimize the switch-case via jump tables.
    // Compilers will ensure this is a perfect hash function, by preventing
    // the two identical cases to exist.
    // The original encoding is described by:
    // Intel SDM Vol. 3C: Table 24-17. Structure of VMCS Component Encoding
    // Our compact encoding is described by:
    // [W WTTI IIII]  W=Width, T=Type, I=Index

    // As of this writing, no VMCS component is encoded with an Index of more
    // than 5 bits (Intel SDM Vol. 3D, Appendix B: Field Encoding in VMCS),
    // even though 9 bits are allocated to Index.
#define HASH(x) \
    (((x) & 0x003E) >> 1) /* Index */ | \
    (((x) & 0x0C00) >> 5) /* Type  */ | \
    (((x) & 0x6000) >> 6) /* Width */
#define CASE(x) \
    case HASH(x): \
        return #x

    switch (HASH(value)) {
    CASE(VMX_PIN_CONTROLS);
    CASE(VMX_PRIMARY_PROCESSOR_CONTROLS);
    CASE(VMX_SECONDARY_PROCESSOR_CONTROLS);
    CASE(VMX_EXCEPTION_BITMAP);
    CASE(VMX_PAGE_FAULT_ERROR_CODE_MASK);
    CASE(VMX_PAGE_FAULT_ERROR_CODE_MATCH);
    CASE(VMX_EXIT_CONTROLS);
    CASE(VMX_EXIT_MSR_STORE_COUNT);
    CASE(VMX_EXIT_MSR_LOAD_COUNT);
    CASE(VMX_ENTRY_CONTROLS);
    CASE(VMX_ENTRY_MSR_LOAD_COUNT);
    CASE(VMX_ENTRY_INTERRUPT_INFO);
    CASE(VMX_ENTRY_EXCEPTION_ERROR_CODE);
    CASE(VMX_ENTRY_INSTRUCTION_LENGTH);
    CASE(VMX_TPR_THRESHOLD);
    CASE(VMX_CR0_MASK);
    CASE(VMX_CR4_MASK);
    CASE(VMX_CR0_READ_SHADOW);
    CASE(VMX_CR4_READ_SHADOW);
    CASE(VMX_CR3_TARGET_COUNT);
    CASE(VMX_CR3_TARGET_VAL_BASE);
    CASE(VMX_VPID);
    CASE(VMX_IO_BITMAP_A);
    CASE(VMX_IO_BITMAP_B);
    CASE(VMX_MSR_BITMAP);
    CASE(VMX_EXIT_MSR_STORE_ADDRESS);
    CASE(VMX_EXIT_MSR_LOAD_ADDRESS);
    CASE(VMX_ENTRY_MSR_LOAD_ADDRESS);
    CASE(VMX_TSC_OFFSET);
    CASE(VMX_VAPIC_PAGE);
    CASE(VMX_APIC_ACCESS_PAGE);
    CASE(VMX_EPTP);
    CASE(VMX_PREEMPTION_TIMER);
    CASE(VMX_INSTRUCTION_ERROR_CODE);
    CASE(VM_EXIT_INFO_REASON);
    CASE(VM_EXIT_INFO_INTERRUPT_INFO);
    CASE(VM_EXIT_INFO_EXCEPTION_ERROR_CODE);
    CASE(VM_EXIT_INFO_IDT_VECTORING);
    CASE(VM_EXIT_INFO_IDT_VECTORING_ERROR_CODE);
    CASE(VM_EXIT_INFO_INSTRUCTION_LENGTH);
    CASE(VM_EXIT_INFO_INSTRUCTION_INFO);
    CASE(VM_EXIT_INFO_QUALIFICATION);
    CASE(VM_EXIT_INFO_IO_ECX);
    CASE(VM_EXIT_INFO_IO_ESI);
    CASE(VM_EXIT_INFO_IO_EDI);
    CASE(VM_EXIT_INFO_IO_EIP);
    CASE(VM_EXIT_INFO_GUEST_LINEAR_ADDRESS);
    CASE(VM_EXIT_INFO_GUEST_PHYSICAL_ADDRESS);
    CASE(HOST_RIP);
    CASE(HOST_RSP);
    CASE(HOST_CR0);
    CASE(HOST_CR3);
    CASE(HOST_CR4);
    CASE(HOST_CS_SELECTOR);
    CASE(HOST_DS_SELECTOR);
    CASE(HOST_ES_SELECTOR);
    CASE(HOST_FS_SELECTOR);
    CASE(HOST_GS_SELECTOR);
    CASE(HOST_SS_SELECTOR);
    CASE(HOST_TR_SELECTOR);
    CASE(HOST_FS_BASE);
    CASE(HOST_GS_BASE);
    CASE(HOST_TR_BASE);
    CASE(HOST_GDTR_BASE);
    CASE(HOST_IDTR_BASE);
    CASE(HOST_SYSENTER_CS);
    CASE(HOST_SYSENTER_ESP);
    CASE(HOST_SYSENTER_EIP);
    CASE(HOST_PAT);
    CASE(HOST_EFER);
    CASE(HOST_PERF_GLOBAL_CTRL);
    CASE(GUEST_RIP);
    CASE(GUEST_RFLAGS);
    CASE(GUEST_RSP);
    CASE(GUEST_CR0);
    CASE(GUEST_CR3);
    CASE(GUEST_CR4);
    CASE(GUEST_ES_SELECTOR);
    CASE(GUEST_CS_SELECTOR);
    CASE(GUEST_SS_SELECTOR);
    CASE(GUEST_DS_SELECTOR);
    CASE(GUEST_FS_SELECTOR);
    CASE(GUEST_GS_SELECTOR);
    CASE(GUEST_LDTR_SELECTOR);
    CASE(GUEST_TR_SELECTOR);
    CASE(GUEST_ES_AR);
    CASE(GUEST_CS_AR);
    CASE(GUEST_SS_AR);
    CASE(GUEST_DS_AR);
    CASE(GUEST_FS_AR);
    CASE(GUEST_GS_AR);
    CASE(GUEST_LDTR_AR);
    CASE(GUEST_TR_AR);
    CASE(GUEST_ES_BASE);
    CASE(GUEST_CS_BASE);
    CASE(GUEST_SS_BASE);
    CASE(GUEST_DS_BASE);
    CASE(GUEST_FS_BASE);
    CASE(GUEST_GS_BASE);
    CASE(GUEST_LDTR_BASE);
    CASE(GUEST_TR_BASE);
    CASE(GUEST_GDTR_BASE);
    CASE(GUEST_IDTR_BASE);
    CASE(GUEST_ES_LIMIT);
    CASE(GUEST_CS_LIMIT);
    CASE(GUEST_SS_LIMIT);
    CASE(GUEST_DS_LIMIT);
    CASE(GUEST_FS_LIMIT);
    CASE(GUEST_GS_LIMIT);
    CASE(GUEST_LDTR_LIMIT);
    CASE(GUEST_TR_LIMIT);
    CASE(GUEST_GDTR_LIMIT);
    CASE(GUEST_IDTR_LIMIT);
    CASE(GUEST_VMCS_LINK_PTR);
    CASE(GUEST_DEBUGCTL);
    CASE(GUEST_PAT);
    CASE(GUEST_EFER);
    CASE(GUEST_PERF_GLOBAL_CTRL);
    CASE(GUEST_PDPTE0);
    CASE(GUEST_PDPTE1);
    CASE(GUEST_PDPTE2);
    CASE(GUEST_PDPTE3);
    CASE(GUEST_DR7);
    CASE(GUEST_PENDING_DBE);
    CASE(GUEST_SYSENTER_CS);
    CASE(GUEST_SYSENTER_ESP);
    CASE(GUEST_SYSENTER_EIP);
    CASE(GUEST_SMBASE);
    CASE(GUEST_INTERRUPTIBILITY);
    CASE(GUEST_ACTIVITY_STATE);
    default:
        return "";
    }
#undef HASH
#undef CASE
}

const char *name_vmx_error(int value)
{
#define CASE(x) \
    case x: return #x

    switch (value) {
    CASE(VMX_ERROR_VMCALL_ROOT);
    CASE(VMX_ERROR_VMCLEAR_PADDR_INVALID);
    CASE(VMX_ERROR_VMCLEAR_VMXON_PTR);
    CASE(VMX_ERROR_VMLAUNCH_VMCS_UNCLEAR);
    CASE(VMX_ERROR_VMRESUME_VMCS_UNLAUNCHED);
    CASE(VMX_ERROR_VMRESUME_AFTER_VMXOFF);
    CASE(VMX_ERROR_ENTRY_CTRL_FIELDS_INVALID);
    CASE(VMX_ERROR_ENTRY_HOST_FIELDS_INVALID);
    CASE(VMX_ERROR_VMPTRLD_PADDR_INVALID);
    CASE(VMX_ERROR_VMPTRLD_VMXON_PTR);
    CASE(VMX_ERROR_VMPTRLD_VMCSREV_INVALID);
    CASE(VMX_ERROR_VMREAD_VMWRITE_INVALID);
    CASE(VMX_ERROR_VMWRITE_READONLY);
    CASE(VMX_ERROR_VMXON_ROOT);
    CASE(VMX_ERROR_ENTRY_VMCS_INVALID);
    CASE(VMX_ERROR_ENTRY_VMCS_UNLAUNCHED);
    CASE(VMX_ERROR_ENTRY_VMCS_NOT_VMXON);
    CASE(VMX_ERROR_VMCALL_VMCS_UNCLEAR);
    CASE(VMX_ERROR_VMCALL_EXIT_INVALID);
    CASE(VMX_ERROR_VMCALL_MSEG_INVALID);
    CASE(VMX_ERROR_VMXOFF_SMM_DUALMONITOR);
    CASE(VMX_ERROR_VMCALL_SMM_INVALID);
    CASE(VMX_ERROR_ENTRY_EXECCTRL_INVALID);
    CASE(VMX_ERROR_ENTRY_MOV_SS);
    CASE(VMX_ERROR_INVEPT_INVALID);
    default:
        return "";
    }
#undef CASE
}

const char *name_vmx_exit(int value)
{
#define CASE(x) \
    case x: return #x

    switch (value) {
    CASE(VMX_EXIT_INT_EXCEPTION_NMI);
    CASE(VMX_EXIT_EXT_INTERRUPT);
    CASE(VMX_EXIT_TRIPLE_FAULT);
    CASE(VMX_EXIT_INIT_EVENT);
    CASE(VMX_EXIT_SIPI_EVENT);
    CASE(VMX_EXIT_SMI_IO_EVENT);
    CASE(VMX_EXIT_SMI_OTHER_EVENT);
    CASE(VMX_EXIT_PENDING_INTERRUPT);
    CASE(VMX_EXIT_PENDING_NMI);
    CASE(VMX_EXIT_TASK_SWITCH);
    CASE(VMX_EXIT_CPUID);
    CASE(VMX_EXIT_GETSEC);
    CASE(VMX_EXIT_HLT);
    CASE(VMX_EXIT_INVD);
    CASE(VMX_EXIT_INVLPG);
    CASE(VMX_EXIT_RDPMC);
    CASE(VMX_EXIT_RDTSC);
    CASE(VMX_EXIT_RSM);
    CASE(VMX_EXIT_VMCALL);
    CASE(VMX_EXIT_VMCLEAR);
    CASE(VMX_EXIT_VMLAUNCH);
    CASE(VMX_EXIT_VMPTRLD);
    CASE(VMX_EXIT_VMPTRST);
    CASE(VMX_EXIT_VMREAD);
    CASE(VMX_EXIT_VMRESUME);
    CASE(VMX_EXIT_VMWRITE);
    CASE(VMX_EXIT_VMXOFF);
    CASE(VMX_EXIT_VMXON);
    CASE(VMX_EXIT_CR_ACCESS);
    CASE(VMX_EXIT_DR_ACCESS);
    CASE(VMX_EXIT_IO);
    CASE(VMX_EXIT_MSR_READ);
    CASE(VMX_EXIT_MSR_WRITE);
    CASE(VMX_EXIT_FAILED_VMENTER_GS);
    CASE(VMX_EXIT_FAILED_VMENTER_MSR);
    CASE(VMX_EXIT_MWAIT);
    CASE(VMX_EXIT_MTF_EXIT);
    CASE(VMX_EXIT_MONITOR);
    CASE(VMX_EXIT_PAUSE);
    CASE(VMX_EXIT_MACHINE_CHECK);
    CASE(VMX_EXIT_TPR_BELOW_THRESHOLD);
    CASE(VMX_EXIT_APIC_ACCESS);
    CASE(VMX_EXIT_GDT_IDT_ACCESS);
    CASE(VMX_EXIT_LDT_TR_ACCESS);
    CASE(VMX_EXIT_EPT_VIOLATION);
    CASE(VMX_EXIT_EPT_MISCONFIG);
    CASE(VMX_EXIT_INVEPT);
    CASE(VMX_EXIT_RDTSCP);
    CASE(VMX_EXIT_VMX_TIMER_EXIT);
    CASE(VMX_EXIT_INVVPID);
    CASE(VMX_EXIT_WBINVD);
    CASE(VMX_EXIT_XSETBV);
    CASE(VMX_EXIT_APIC_WRITE);
    CASE(VMX_EXIT_RDRAND);
    CASE(VMX_EXIT_INVPCID);
    CASE(VMX_EXIT_VMFUNC);
    CASE(VMX_EXIT_ENCLS);
    CASE(VMX_EXIT_RDSEED);
    CASE(VMX_EXIT_XSAVES);
    CASE(VMX_EXIT_XRSTORS);
    default:
        return "";
    }
#undef CASE
}
